package com.fengzheng.basic.common.config.response.exception;

import com.fengzheng.basic.common.config.response.ResultBean;
import com.fengzheng.basic.common.config.response.ResultCodeMsg;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.ConstraintViolationImpl;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liht
 * @date 2022/3/25 2:54 下午
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 全局异常处理
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object defaultExceptionHandler(HttpServletResponse response, Exception e) {
        log.error("error: {}", e.getMessage(), e);
        if (e instanceof ServiceException) {
            response.setStatus(((ServiceException)e).getHttpCode());
            return new ResultBean<>(e);
        } else {
            ServiceException exception = new ServiceException(ResultCodeMsg.SYSTEM_ERROR);
            response.setStatus(exception.getHttpCode());
            return new ResultBean<>(exception);
        }
    }

    /**
     * 404
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseBody
    public Object notFoundExceptionHandler() {
        return new ResultBean<>(new ServiceException(ResultCodeMsg.API_NOT_FOUND));
    }

    /**
     * 权限拒绝
     */
    @SneakyThrows
    @ExceptionHandler(AccessDeniedException.class)
    public void accessDeniedExceptionHandler(Exception e) {
        throw e;
    }

    /**
     * 对象参数验证不通过，全局处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Object argumentNotValidExceptionHandler(Exception e) {
        MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException)e;
        List<String> defaultMsg = methodArgumentNotValidException.getBindingResult().getAllErrors().stream()
                .map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        return new ResultBean<>(new ServiceException(defaultMsg.get(0)));
    }

    /**
     * controller行内参数验证不通过，全局处理
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Object inlineArgumentNotValidExceptionHandler(Exception e) {
        ConstraintViolationException constraintViolationException = (ConstraintViolationException)e;
        List<String> defaultMsg = constraintViolationException.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessageTemplate).collect(Collectors.toList());
        return new ResultBean<>(new ServiceException(defaultMsg.get(0)));
    }

}
